package com.sinszm;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sinszm.domain.NodeData;
import org.dom4j.*;
import org.dom4j.dom.DOMAttribute;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toMap;

/**
 * XML内容读写工具
 *
 * @author admin
 * @date 2022/01/21
 */
public class DomXmlUtils {

    /**
     * 节点树格式
     *
     * @param list 列表
     * @return {@link List<NodeData>}
     */
    private static List<NodeData> nodeTreeFormat(List<NodeData> list) {
        if (ObjectUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        //存储结构转换一下
        Map<String, NodeData> map = list.stream()
                .filter(Objects::nonNull)
                .filter(db -> StrUtil.isNotEmpty(db.getId()))
                .collect(toMap(NodeData::getId, a -> a, (k1, k2) -> k1));
        //返回树
        List<NodeData> result = new ArrayList<>();
        //遍历处理存储树结构逻辑
        for (NodeData tree : list) {
            if (StrUtil.isNotEmpty(tree.getPid())) {
                NodeData temp = map.get(tree.getPid());
                if (temp == null) {
                    continue;
                }
                List<NodeData> childList = temp.getChild();
                childList.add(tree);
                temp.setChild(childList);
                continue;
            }
            result.add(tree);
        }
        return result;
    }

    /**
     * 元素构建
     *
     * @param root     根
     * @param element  元素
     * @param nodeData 节点数据
     */
    private static void element(Element root, Element element, NodeData nodeData) {
        //处理参数
        Map<String, String> namespaces = Optional.ofNullable(nodeData.getNamespaces()).orElse(new HashMap<>(0));
        Map<String, String> attributes = Optional.ofNullable(nodeData.getAttributes()).orElse(new HashMap<>(0));
        String value = StrUtil.trimToEmpty(nodeData.getValue());
        List<NodeData> children = Optional.ofNullable(nodeData.getChild()).orElse(new ArrayList<>());
        //命名空间处理
        for (Map.Entry<String, String> entry : namespaces.entrySet()) {
            element.addNamespace(StrUtil.trimToEmpty(entry.getKey()), StrUtil.trimToEmpty(entry.getValue()));
        }
        //属性处理
        List<Attribute> attrs = attributes.entrySet()
                .stream()
                .filter(pre -> StrUtil.isNotEmpty(pre.getValue()))
                .map(pre -> new DOMAttribute(new QName(StrUtil.trimToEmpty(pre.getKey())), StrUtil.trimToEmpty(pre.getValue())))
                .collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(attrs)) {
            element.setAttributes(attrs);
        }
        //值文本处理
        if (!value.isEmpty()) {
            element.setText(value);
        }
        //处理子节点
        if (ObjectUtil.isNotEmpty(children)) {
            for (NodeData child : children) {
                Element childElement = element.addElement(child.getName());
                element(element, childElement, child);
            }
        }
    }

    /**
     * 创建文档
     *
     * @param root       根
     * @param listParams 列表
     * @return {@link Document}
     */
    private static Document createDocument(Element root, List<NodeData> listParams) {
        if (ObjectUtil.isEmpty(listParams)) {
            return null;
        }
        List<NodeData> list = nodeTreeFormat(
                Optional.ofNullable(listParams)
                        .orElse(new ArrayList<>())
                        .stream()
                        .peek(d -> d.setChild(d.getChild() == null ? new ArrayList<>() : d.getChild()))
                        .collect(Collectors.toList())
        ).stream().filter(Objects::nonNull).collect(Collectors.toList());
        Document document = root == null ? DocumentHelper.createDocument() : DocumentHelper.createDocument(root);
        for (NodeData nodeData : list) {
            if (StrUtil.isEmpty(nodeData.getName())) {
                continue;
            }
            //处理Dom对象
            Element element;
            if (root == null) {
                document.setRootElement(DocumentHelper.createElement(nodeData.getName()));
            }
            element = document.getRootElement();
            element(null, element, nodeData);
        }
        return document;
    }

    /**
     * 创建xml文本
     *
     * @param root 根
     * @param list 列表
     * @return {@link String}
     */
    public static String createXmlText(Element root, List<NodeData> list) {
        Document document = createDocument(root, list);
        if (document != null) {
            return document.asXML()
                    .replace("xmlns=\"\"", "")
                    .replace("  ", " ");
        }
        return "";
    }

}
